#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include "rational.h"

/* Arithmetic Operations */

rational rAdd(rational arg1, rational arg2) {
    
    rational sum;
    
    arg1 = rCheckNegative(arg1);
    arg2 = rCheckNegative(arg2);

    if (rCheckValid(arg1) && rCheckValid(arg2)) {
        sum.numerator = arg1.numerator * arg2.denominator + arg1.denominator * arg2.numerator;
        sum.denominator = arg1.denominator * arg2.denominator;
    } else {
        sum = rNull();
    }

    sum = rReduce(rCheckNegative(sum));
    
    return sum;
}

rational rSub(rational arg1, rational arg2) {
    
    rational difference;
    
    arg1 = rCheckNegative(arg1);
    arg2 = rCheckNegative(arg2);

    if (rCheckValid(arg1) && rCheckValid(arg2)) {
        difference.numerator = arg1.numerator * arg2.denominator - arg1.denominator * arg2.numerator;
        difference.denominator = arg1.denominator * arg2.denominator;
    } else {
        difference = rNull();
    }
    
    difference = rReduce(rCheckNegative(difference));

    return difference;
    
}

rational rMul(rational arg1, rational arg2) {
    
    rational product;
    
    arg1 = rCheckNegative(arg1);
    arg2 = rCheckNegative(arg2);
    
    if (rCheckValid(arg1) && rCheckValid(arg2)) {
        product.numerator = arg1.numerator * arg2.numerator;
        product.denominator = arg1.denominator * arg2.denominator;
    } else {
        product = rNull();
    }
    
    product = rReduce(rCheckNegative(product));
    
    return product;
    
}

rational rDiv(rational arg1, rational arg2) {
    
    rational quotient;
    
    arg1 = rCheckNegative(arg1);
    arg2 = rCheckNegative(arg2);
    
    if (rCheckValid(arg1) && rCheckValid(arg2) && (arg2.numerator != 0)) {
        quotient.numerator = arg1.numerator * arg2.denominator;
        quotient.denominator = arg1.denominator * arg2.numerator;
    } else {
        quotient = rNull();
    }
    
    quotient = rReduce(rCheckNegative(quotient));
    
    return quotient;
    
}

/* Comparison Operations */

int rE(rational arg1, rational arg2) {
    
    int equal;
    
    arg1 = rCheckNegative(arg1);
    arg2 = rCheckNegative(arg2);
    
    if (rCheckValid(arg1) && rCheckValid(arg2)) {
        equal = arg1.numerator * arg2.denominator - arg1.denominator * arg2.numerator;
        equal = (equal == 0)? 1 : 0;
    } else {
        equal = rError();
    }
    
    return equal;
    
}

int rLt(rational arg1, rational arg2) {
    
    int lessThan;
    
    arg1 = rCheckNegative(arg1);
    arg2 = rCheckNegative(arg2);
    
    if (rCheckValid(arg1) && rCheckValid(arg2)) {
        lessThan = arg1.numerator * arg2.denominator - arg1.denominator * arg2.numerator;
        lessThan = (lessThan < 0) ? 1 : 0;
    } else {
        lessThan = rError();
    }
    
    return lessThan;
    
}

int rGt(rational arg1, rational arg2) {
    
    int greaterThan;
    
    arg1 = rCheckNegative(arg1);
    arg2 = rCheckNegative(arg2);
    
    if (rCheckValid(arg1) && rCheckValid(arg2)) {
        greaterThan = arg1.numerator * arg2.denominator - arg1.denominator * arg2.numerator;
        greaterThan = (greaterThan > 0) ? 1 : 0;
    } else {
        greaterThan = rError();
    }
    
    return greaterThan;
    
}

int rLtE(rational arg1, rational arg2) {
    
    int lessThanEqual;
    
    arg1 = rCheckNegative(arg1);
    arg2 = rCheckNegative(arg2);
    
    if (rCheckValid(arg1) && rCheckValid(arg2)) {
        lessThanEqual = arg1.numerator * arg2.denominator - arg1.denominator * arg2.numerator;
        lessThanEqual = (lessThanEqual <= 0) ? 1 : 0;
    } else {
        lessThanEqual = rError();
    }
    
    return lessThanEqual;
    
}

int rGtE(rational arg1, rational arg2) {
    
    int greaterThanEqual;
    
    arg1 = rCheckNegative(arg1);
    arg2 = rCheckNegative(arg2);
    
    if (rCheckValid(arg1) && rCheckValid(arg2)) {
        greaterThanEqual = arg1.numerator * arg2.denominator - arg1.denominator * arg2.numerator;
        greaterThanEqual = (greaterThanEqual >= 0) ? 1 : 0;
    } else {
        greaterThanEqual = rError();
    }
    
    return greaterThanEqual;
    
}

/* Conversion Operations */

/*
 * Operation to convert Integer to Rational
 */
extern rational itor(int intNum) {
    
    rational val;
    
    val.numerator = intNum;
    val.denominator = 1;
    
    return val;
}

/* Error Handling Operations*/

int rError() {
    return -1;
}

rational rNull() {
    
    rational val;
    
    val.numerator = 1;
    val.denominator = 0;
    
    return val;
}

int rCheckNull(rational num) {
    
    return rCheckValid(num);
    
}

int rCheckValid(rational num) {
    
    return (num.denominator != 0);
    
}

rational rCheckNegative(rational num) {
    
    if (num.denominator < 0) {
        num.numerator = (-1) * num.numerator;
        num.denominator = (-1) * num.denominator;
    }
    
    return num;
    
}

/* Display Procedures */

void printRational(rational num) {
    
    if (rCheckValid(num)) {
        printf("%2d/%d",num.numerator,num.denominator);
    } else {
        printf("(infinity)");
    }
    
    return;
}

/* Other utility operations */

rational rReduce(rational num) {
    
    int absNum,absDenom,gcdNumDenom;
    rational reducedVal;
    
    absNum = abs(num.numerator);
    absDenom = abs(num.denominator);
    gcdNumDenom = gcd(absNum, absDenom);
    
    reducedVal.numerator = num.numerator/gcdNumDenom;
    reducedVal.denominator = num.denominator/gcdNumDenom;
    
    return reducedVal;
    
}

int gcd(int arg1, int arg2) {
    
    int tmp;
    while(1)
    {
  	tmp = arg1%arg2;
  	if(tmp==0)
  	  return arg2;
  	arg1 = arg2;
  	arg2 = tmp;
    }
}